#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include "logsFunctions.h"

    const char *  REGISTER      =  "REGISTER";
    const char *  LOGIN         =  "LOGIN";
    const char *  PASS          =  "PASS";
    const char *  LISTPRIV      =  "LISTPRIV";
    const char *  LISTGROUP     =  "LISTGROUP";
    const char *  LISTGROUPS    =  "LISTGROUPS";
    const char *  LISTUSRGROUPS =  "LISTUSRGROUPS";
    const char *  GETPRIVMSG    =  "GETPRIVMSG";
    const char *  GETGRMSG      =  "GETGRMSG";
    const char *  GETGROUPS     =  "GETGROUPS";
    const char *  GETUSRGROUPS  =  "GETUSRGROUPS";
    const char *  SETUSRGROUP   =  "SETUSRGROUP";
    const char *  SETGROUP      =  "SETGROUP";
    const char *  MODGROUP      =  "MODGROUP";
    const char *  SENDMSG       =  "SENDMSG";
    const char *  LISTMYMSG     =  "LISTMYMSG";
    const char *  GETMYMSG      =  "GETMYMSG";
    const char *  DELMYMSG      =  "DELMYMSG";
    const char *  SELECTED      =  "SELECTED";
    const char *  INCORECTPASS  =  "INCORECTPASS";
    const char *  USREXISTS     =  "USREXISTS";
    const char *  NOUSER        =  "NOUSER";
    const char *  LOGED         =  "LOGED";
    const char *  WRONGPASS     =  "WRONGPASS";
    const char *  NOACCESS      =  "NOACCESS";
    const char *  NOMSG         =  "NOMSG";
    const char *  USRGRADD      =  "USRGRADD";
    const char *  GRCREATE      =  "GRCREATE";
    const char *  GREXISTS      =  "GREXISTS";
    const char *  MSGSENT       =  "MSGSENT";
    const char *  WRONGDEST     =  "WRONGDEST";
    const char *  MSGDELETED    =  "MSGDELETED";
    const char *  HELLO         =  "HELLO";
    const char *  OK            =  "OK";
    const char *  KO            =  "KO";
    const char *  KORESPONSE    =  "BADRESPONSE";
    const char *  DBERROR       =  "DBERROR";
    const char *  WRONGARG      =  "WRONGARG";

    struct Header
    {
        char userType;
        char receiver[32];
        char sender[32];
        int  bytesOfMessage;
        char date[20];
        char messageAlreadyRead;
    };
    
    sqlite3 * sqlServerHandle;

    long commandNumber=0;

    int getMessageSize(const char * sentence)
    {
        int count = 0;
        while(sentence[count]!='\0')
        {
            count++;
        }

        return count+1;
    }

    char * getCharHeader(struct Header * structHeader)
    {
        char * result = (char*)malloc(sizeof(*structHeader)+1);
        result[0] = structHeader->userType;
        int i=1;
        int zeroBased=0;
        int spaces=0;

        //receiver, i=1
        for(zeroBased=0;zeroBased<32;zeroBased++)
        {
            if((structHeader->receiver[zeroBased] != ' ') && (structHeader->receiver[zeroBased] != '\0') && (spaces==0))
            {
                result[i++] = structHeader->receiver[zeroBased];
            }
            else
            {
                spaces = 1;
                result[i++] = ' ';
            }
        }

        spaces = 0;
        //sender, i=33
        for(zeroBased=0;zeroBased<32;zeroBased++)
        {
            if((structHeader->sender[zeroBased] != ' ') && (structHeader->sender[zeroBased] != '\0') && (spaces==0))
            {
                result[i++] = structHeader->sender[zeroBased];
            }
            else
            {
                 spaces=1;
                result[i++] = ' ';
            }
        }

        spaces=0;
        // bytesOfMessage,i=65
        char number[4];
        sprintf(number,"%d",structHeader->bytesOfMessage);
        for(zeroBased=0;zeroBased<4;zeroBased++)
        {
            if((number[zeroBased] != ' ') && (number[zeroBased] != '\0')  && (spaces==0))
            {
                result[i++] = number[zeroBased];
            }
            else
            {
                spaces=1;
                result[i++] = ' ';
            }
        }

        spaces=0;
        //date, i=69
        for(zeroBased=0;zeroBased<20;zeroBased++)
        {
            if((structHeader->date[zeroBased] != '\0') && (spaces==0))
            {
                result[i++] = structHeader->date[zeroBased];
            }
            else
            {
                spaces=1;
                result[i++] = ' ';
            }
        }

        //message read, i=89
        result[i++] = structHeader->messageAlreadyRead;
        result[i] = '\0';

       // i=90;

        return result;
    }

    // int = 90 is good. Less means, that a \0 char was at returned position
    int getHeaderFromChar(char * header,struct  Header* structHeader)
    {
        structHeader->userType = header[0];
        int i=1;
        int zeroBased=0;

        //receiver, i=1
        while(header[i]!=' ')
        {
            if(header[i]=='\0')
            {
                return i;
            }
            structHeader->receiver[zeroBased++] = header[i++];
        }

        structHeader->receiver[zeroBased] = '\0';


        //sender, i=33
        i=33;
        zeroBased = 0;
        while(header[i]!=' ')
        {
            if(header[i]=='\0')
            {
                return i;
            }
            structHeader->sender[zeroBased++] = header[i++];
        }

        structHeader->sender[zeroBased] = '\0';


        
        // bytesOfMessage,i=65
        char number[4];
        i=65;
        zeroBased = 0;
        while(header[i]!=' ')
        {
            if(header[i]=='\0')
            {
                return i;
            }
            number[zeroBased++] = header[i++];
        }

        structHeader->bytesOfMessage = atoi(number);
        if(structHeader->bytesOfMessage<=0)
        {
            return i;
        }



        //date, i=69
        i=69;
        zeroBased = 0;
        int endit = 0;
        while(endit!=2)
        {
            if(header[i]=='\0')
            {
                return i;
            }
            if(header[i+1]==' ') endit++; //there is one whitespace in the date string
            structHeader->date[zeroBased++] = header[i++];
        }

        structHeader->date[zeroBased] = '\0'; 


        //message read, i=89
        structHeader->messageAlreadyRead = '0';

       // i=90;
        i=90;

        return i;
    }

    long getCommandNumber()
    {
        if(commandNumber==10000)
            commandNumber = 0;

        return commandNumber++;
    }

    // 0 - ok
    // else - not ok
    int SetDatabaseConnection(char * connectionString)
    {
        FILE * file = fopen(connectionString, "r");
        if (file) {
            fclose(file);
        }
        else
        {
            return -1;
        }

        int result = sqlite3_open(connectionString,&sqlServerHandle);
        return result;
    }

    void ShutdownDatabase()
    {
        sqlite3_close(sqlServerHandle);
    }

    char * GetMD5(char * pass)
    {
        //TODO - md5 hash
        return pass;
    }

    char * ResponseRegister(char * command, int *loginState)
    {
        int returnValue;

        char user[32];
        char pass1[32];
        //char pass2[32];
        char * answer = (char *)malloc(50);
        char * query  = (char *)malloc(100);

        //returnValue = sscanf(command,"%s %s %s",user,pass1,pass2);
        returnValue = sscanf(command,"%s %s",user,pass1);

        // Wrong command syntax
        if (returnValue != 2) //change to 3, if pass2 validation is needed
        {
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        // check password repeat
/*
        if(strcmp(pass1,pass2) != 0)
        {
            sprintf(answer,"%s%ld %s %s",OK,getCommandNumber(),INCORECTPASS,user);
            return answer;
        }
*/

        // Check if user exists
        sqlite3_stmt *statement;
        sprintf(query,"SELECT COUNT(*) AS found FROM Users WHERE Login = '%s'",user);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //USER EXISTS
                    if(val!=0)
                    {
                        sprintf(answer,"%s%ld %s",OK,getCommandNumber(),USREXISTS);
                        return answer;
                    }
                }
            } else if (returnValue == SQLITE_DONE) {
                // All rows finished
                //printf("All rows fetched\n");
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        // If nothing's wrong, create a new user and login him
        sprintf(query,"INSERT INTO Users VALUES (NULL,'%s','%s',datetime('now'))",user,GetMD5(pass1));
        returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);

        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // GET USERS ID
        sprintf(query,"SELECT Id FROM Users WHERE Login = '%s'",user);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //USER EXISTS
                    if(val>0)
                    {
                        *loginState = val;
                    }
                }
            } else if (returnValue == SQLITE_DONE) {
                // All rows finished
                //printf("All rows fetched\n");
                
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        if(*loginState>0)
        {
            sprintf(query,"INSERT INTO UsersInGroups VALUES (%d,1)",*loginState);
            returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);
        }
        
        free(query);

        sprintf(answer,"%s%ld %s %s",OK,getCommandNumber(),SELECTED,user);
        return answer;
    }

    char * ResponseLogin(char * command, int *loginState)
    {
        int returnValue;
        *loginState = 0;

        char user[32];
        char pass[32];
        char * answer = (char *)malloc(50);
        char * query  = (char *)malloc(100);

        returnValue = sscanf(command,"%s %s",user,pass);

        // Wrong command syntax
        if (returnValue != 2)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        // Check if user exists
        sqlite3_stmt *statement;
        sprintf(query,"SELECT Id FROM Users WHERE Login = '%s' AND Pass = '%s'",user,GetMD5(pass));
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //USER EXISTS
                    if(val>0)
                    {
                        *loginState = (int)val;
                        sprintf(answer,"%s%ld %s %s",OK,getCommandNumber(),LOGED,user);
                    }
                }
            } else if (returnValue == SQLITE_DONE) {

                if(*loginState == 0)
                {
                    sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
                }

               
                break;
            } else {
                // Some error encountered
                
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        sprintf(query,"UPDATE Users SET Last_Activity = DATETIME('now') WHERE Id = %d",*loginState);
        returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);
        if(returnValue) //probably user exists in the group
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
        }
        free(query);

        return answer;
    }

    char * ResponsePassword(char * command, int *loginState)
    {
        int returnValue;
        char pass[32];
        char * answer = (char *)malloc(50);
        char * query  = (char *)malloc(100);

        if(*loginState >= 0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%s",pass);

        // Wrong command syntax
        if (returnValue != 1)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        // Check if user exists
        sqlite3_stmt *statement;
        int id = -(*loginState);
        sprintf(query,"SELECT Login FROM Users WHERE Id = '%d' AND Pass = '%s'",id,GetMD5(pass));
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const char *val = (const char*) sqlite3_column_text(statement, col);

                    //USER EXISTS
                        *loginState = -(*loginState);
                        sprintf(answer,"%s%ld %s %s",OK,getCommandNumber(),LOGED,val);
                }
            } else if (returnValue == SQLITE_DONE) {

                if(*loginState <= 0)
                {
                    sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGPASS);
                }
                
                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        return answer;
    }

    char * ResponseHello()
    {
        char * answer = (char *)malloc(20);
        sprintf(answer,"%s%ld %s",OK,getCommandNumber(),HELLO);
        return answer;
    }

    // LISTPRIV
    // Gives the number of messages that are sent directly to the user
    // loginState - logged user ID
    char * ResponseListMyPrivateMessages(int *loginState)
    {
        int returnValue;

        char * answer = (char *)malloc(50);
        char * query  = (char *)malloc(200);

        int result = 0;

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        // Check the number
        sqlite3_stmt *statement;
        sprintf(query,"SELECT COUNT(*) as privmsg FROM Messages WHERE Receiver_Id = %d AND Receiver_Type = 0 AND Expire_Date >= DATETIME('now')",*loginState);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //has private messages
                    if(val>=0)
                    {
                        result = (int)val;
                    }
                }
            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        sprintf(answer,"%s%ld %d",OK,getCommandNumber(),result);
        return answer;
    }

    // LISTGROUP num
    // Gives the number of messages in the group 'num', from the groups in which
    // the user is signed in
    char * ResponseListMyGroupMessages(char * command, int *loginState)
    {
        int returnValue;
        int groupid;
        char * answer = (char *)malloc(50);
        char * query  = (char *)malloc(300);

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }


        returnValue = sscanf(command,"%d",&groupid);

        // Wrong command syntax
        if (returnValue != 1)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;


        // Check if user has permission (is in the group with the id groupid)
        sqlite3_stmt *statement;
        sprintf(query,"SELECT COUNT(*) as perm FROM UsersInGroups WHERE Users_Id=%d",*loginState);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //has private messages
                    if(val<=groupid)
                    {
                        sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOACCESS);
                        free(query);
                        return answer;
                    }
                }
            } else if (returnValue == SQLITE_DONE) {

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        // Check the number of messages in groupid
        sprintf(query,"SELECT COUNT(*) as privmsg FROM Messages WHERE Receiver_Groups_Id = (SELECT Groups_Id FROM UsersInGroups WHERE Users_Id = %d ORDER BY Groups_Id LIMIT %d,1) AND Receiver_Type = 1 AND Expire_Date >= DATETIME('now')",*loginState,groupid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //has private messages
                    if(val>=0)
                    {
                        result = (int)val;
                    }
                }
            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        sprintf(answer,"%s%ld %d",OK,getCommandNumber(),result);
        return answer;
    }

    // LISTGROUPS
    // Gives the number of all groups. Private, public, private without access
    // but the groups the user is not in
    char * ResponseListAllGroups(int *loginState)
    {
        int returnValue;
        char * answer = (char *)malloc(50);
        char * query  = (char *)malloc(200);

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        int result = 0;


        // Check if user has permission (is in the group with the id groupid)
        sqlite3_stmt *statement;
        sprintf(query,"SELECT COUNT(*) as groups FROM Groups");
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //has private messages
                    if(val>=0)
                    {
                        result = (int)val;
                    }
                }
            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        sprintf(answer,"%s%ld %d",OK,getCommandNumber(),result);
        return answer;
    }

    // LISTUSRGROUPS
    // gives the number of groups, in which the user is signed in.
    char * ResponseListMyGroups(int * loginState)
    {
        int returnValue;
        char * answer = (char *)malloc(50);
        char * query  = (char *)malloc(200);

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }
        
        int result = 0;


        // Check the group
        sqlite3_stmt *statement;
        sprintf(query,"SELECT COUNT(*) as groups FROM UsersInGroups WHERE Users_Id=%d",*loginState);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //group messages
                    if(val>=0)
                    {
                        result = (int)val;
                    }
                }
            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        sprintf(answer,"%s%ld %d",OK,getCommandNumber(),result);
        return answer;
    }


    // GETPRIVMSG
    // Gets the private users message behind the given in command 'num'
    char * ResponseGetSpecificPrivateMessage(char * command, int * loginState)
    {
        int returnValue;
        int msgid=0;
        char * answer = (char *)malloc(400);
        char * query  = (char *)malloc(300);

        struct Header msgHeader;
        char message[300];

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%d",&msgid);

        // Wrong command syntax
        if (returnValue != 1)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;


        // het the message
        sqlite3_stmt *statement;
        sprintf(query,"SELECT msg.Id,msg.Send_Date,rec.Login,snd.Login,msgc.Message_Text FROM Messages AS msg INNER JOIN MessageContents AS msgc ON msg.Id = msgc.Messages_Id INNER JOIN Users AS rec ON msg.Receiver_Id = rec.Id INNER JOIN Users AS snd ON msg.Sender_Id = snd.Id WHERE rec.Id = %d ORDER BY msg.Id LIMIT %d,1",*loginState,msgid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
               
                    // Set the header
                    const int *Id = (const int*) sqlite3_column_int(statement, 0);
                    const char *date = (const char*) sqlite3_column_text(statement,1);
                    const char *sender = (const char*) sqlite3_column_text(statement,2);
                    const char *receiver = (const char*) sqlite3_column_text(statement,3);
                    const char *msgtxt = (const char*) sqlite3_column_text(statement,4);
                    
                    msgHeader.bytesOfMessage = getMessageSize(msgtxt);
                    strcpy(msgHeader.date,date);
                    msgHeader.messageAlreadyRead='0';
                    strcpy(msgHeader.sender,sender);
                    strcpy(msgHeader.receiver,receiver);
                    msgHeader.userType = '0';
                    strcpy(message,msgtxt);
                    result = 1;
               
            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        if(result == 1)
        {
            sprintf(answer,"%s%ld %s %s",OK,getCommandNumber(),getCharHeader(&msgHeader),message);
        }
        else
        {
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOMSG);
        }
        
        return answer;
    }

    char * ResponseGetSpecificGroupMessage(char * command, int * loginState)
    {
        int returnValue;
        int msgid=0;
        int groupid=0;
        char * answer = (char *)malloc(400);
        char * query  = (char *)malloc(400);

        struct Header msgHeader;
        char message[300];

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%d %d",&groupid,&msgid);

        // Wrong command syntax
        if (returnValue != 2)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;


        // het the message
        sqlite3_stmt *statement;
        sprintf(query,"SELECT msg.Id,msg.Send_Date,rec.Name,snd.Login,msgc.Message_Text FROM Messages AS msg INNER JOIN MessageContents AS msgc ON msg.Id = msgc.Messages_Id INNER JOIN Groups AS rec ON msg.Receiver_Groups_Id = rec.Id INNER JOIN Users AS snd ON msg.Sender_Id = snd.Id WHERE rec.Id = (SELECT Groups_Id FROM UsersInGroups WHERE Users_Id=%d ORDER BY Groups_Id LIMIT %d,1) ORDER BY msg.Id LIMIT %d,1",*loginState,groupid,msgid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // Set the header
                    const int *Id = (const int*) sqlite3_column_int(statement, 0);
                    const char *date = (const char*) sqlite3_column_text(statement,1);
                    const char *sender = (const char*) sqlite3_column_text(statement,2);
                    const char *receiver = (const char*) sqlite3_column_text(statement,3);
                    const char *msgtxt = (const char*) sqlite3_column_text(statement,4);

                    msgHeader.bytesOfMessage = getMessageSize(msgtxt);
                    strcpy(msgHeader.date,date);
                    msgHeader.messageAlreadyRead='0';
                    strcpy(msgHeader.sender,sender);
                    strcpy(msgHeader.receiver,receiver);
                    msgHeader.userType = '1';
                    strcpy(message,msgtxt);
                    result = 1;

            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        if(result == 1)
        {
            sprintf(answer,"%s%ld %s %s",OK,getCommandNumber(),getCharHeader(&msgHeader),message);
        }
        else
        {
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOMSG);
        }

        return answer;
    }

    // GETGROUPS num
    char * ResponseSpecificGroup(char * command, int * loginState)
    {
        int returnValue;
        int groupid=0;
        char * answer = (char *)malloc(100);
        char * query  = (char *)malloc(200);
        
        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%d",&groupid);

        // Wrong command syntax
        if (returnValue != 1)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;


        // het the message
        sqlite3_stmt *statement;
        sprintf(query,"SELECT groups.Name, user.Login, groups.Private FROM Groups AS groups INNER JOIN Users AS user ON groups.Owner_Id = user.Id ORDER BY groups.Id LIMIT %d,1",groupid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // get info
                    const char *name = (const char*) sqlite3_column_text(statement,0);
                    const char *owner = (const char*) sqlite3_column_text(statement,1);
                    const int *private = (const int*) sqlite3_column_int(statement,2);

                    sprintf(answer,"%s%ld %s %s %d",OK,getCommandNumber(),name,owner,private);
                    
                    result = 1;

            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        if(result != 1)
        {
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
        }

        return answer;
    }

    // GETUSRGROUPS
    char * ResponseSpecificUserGroup(char * command, int * loginState)
    {
        int returnValue;
        int groupid=0;
        char * answer = (char *)malloc(100);
        char * query  = (char *)malloc(400);

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%d",&groupid);

        // Wrong command syntax
        if (returnValue != 1)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;


        // het the message
        sqlite3_stmt *statement;
        sprintf(query,"SELECT groups.Name, user.Login, groups.Private FROM Groups AS groups INNER JOIN Users AS user ON groups.Owner_Id = user.Id INNER JOIN UsersInGroups AS uig ON uig.Groups_Id = groups.Id WHERE uig.Users_Id = %d ORDER BY groups.Id LIMIT %d,1",*loginState,groupid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // get info
                    const char *name = (const char*) sqlite3_column_text(statement,0);
                    const char *owner = (const char*) sqlite3_column_text(statement,1);
                    const int *private = (const int*) sqlite3_column_int(statement,2);

                    sprintf(answer,"%s%ld %s %s %d",OK,getCommandNumber(),name,owner,private);

                    result = 1;

            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        if(result != 1)
        {
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
        }

        return answer;
    }

    // SETUSRGROUP
    char * ResponseSetUserToGroup(char * command, int * loginState)
    {
        int returnValue;
        int groupid=0;
        char userid[32];
        char * answer = (char *)malloc(100);
        char * query  = (char *)malloc(200);

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%s %d",userid,&groupid);

        // Wrong command syntax
        if (returnValue != 2)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;
        int newuserid=0;


        // get the user
        sqlite3_stmt *statement;
        sprintf(query,"SELECT Id FROM Users WHERE Login='%s'",userid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // get info
                    const int *id = (const int*) sqlite3_column_int(statement,0);

                    newuserid = (int)id;
                    

            } else if (returnValue == SQLITE_DONE) {

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        if(newuserid==0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
            return answer;
        }

        // get the group
        sprintf(query,"SELECT Id, Private, Owner_Id FROM Groups ORDER BY Id LIMIT %d,1",groupid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // get info
                    const int *id = (const int*) sqlite3_column_int(statement,0);
                    const int *private = (const int*) sqlite3_column_int(statement,1);
                    const int *owner = (const int*) sqlite3_column_int(statement,2);

                    if(private == 0)
                    {
                        if(newuserid==*loginState) // to a public group Im the only one that can add myself to it
                        {
                            result = (int)id;
                        }
                    }
                    else
                    {
                        if(owner==*loginState) // to add users to a private group I have to be the owner
                        {
                            result = (int)id;
                        }
                    }

            } else if (returnValue == SQLITE_DONE) {

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        // No access
        if(result == 0)
        {
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOACCESS);
            return answer;
        }


        // set the user in group
        sprintf(query,"INSERT INTO UsersInGroups VALUES (%d,%d)",newuserid,result);
        returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);
        if(returnValue) //probably user exists in the group
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
            return answer;
        }

        free(query);

        sprintf(answer,"%s%ld %s",OK,getCommandNumber(),USRGRADD);
        return answer;
    }

    char * ResponseSetNewGroup(char * command, int * loginState)
    {
        int returnValue;
        char groupname[32];
        int private=0;
        char * answer = (char *)malloc(100);
        char * query  = (char *)malloc(200);

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%s %d",groupname,&private);

        // Wrong command syntax
        if (returnValue != 2)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;


        // het the message
        sqlite3_stmt *statement;
        sprintf(query,"SELECT COUNT(*) FROM Groups WHERE Name='%s'",groupname);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // get info
                    const int *count = (const int*) sqlite3_column_int(statement,0);

                    if(count > 0)
                    {
                         free(query);
                         sprintf(answer,"%s%ld %s",OK,getCommandNumber(),GREXISTS);
                         return answer;
                    }

            } else if (returnValue == SQLITE_DONE) {

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        // create new group
        sprintf(query,"INSERT INTO Groups VALUES (NULL,'%s',%d,%d); INSERT INTO UsersInGroups VALUES (%d,last_insert_rowid())",groupname,private,*loginState,*loginState);
        returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

/*
        sprintf(query,"INSERT INTO UsersInGroups VALUES (%d,%d)",groupname,private,*loginState);
        returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }
*/

        free(query);

        sprintf(answer,"%s%ld %s",OK,getCommandNumber(),GRCREATE);
        return answer;
    }

    char * ResponseModifyExistingGroup(char * command, int * loginState)
    {
        int returnValue;
        int groupid=0;
        char groupname[32];
        int private=0;
        char * answer = (char *)malloc(100);
        char * query  = (char *)malloc(200);

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%d %s %d",&groupid,groupname,&private);

        // Wrong command syntax
        if (returnValue != 3)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;


        // het the message
        sqlite3_stmt *statement;
        sprintf(query,"SELECT Id,Owner_Id FROM Groups ORDER BY Id LIMIT %d,1",groupid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // get info
                    const int *id = (const int*) sqlite3_column_int(statement,0);
                    const int *owner = (const int*) sqlite3_column_int(statement,1);
                    result = (int)id;

                    if(owner != *loginState)
                    {
                         free(query);
                         sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOACCESS);
                         return answer;
                    }

            } else if (returnValue == SQLITE_DONE) {

                if(result == 0)
                {
                         sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
                         return answer;
                }

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        // modyfie group
        sprintf(query,"UPDATE Groups SET Name='%s', Private=%d WHERE Id=%d",groupname,private,result);
        returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        free(query);

        sprintf(answer,"%s%ld %s %d",OK,getCommandNumber(),groupname,private);
        return answer;
    }

    char * ResponseSendMessage(char * command, int * loginState)
    {
        int returnValue;

        char * answer = (char *)malloc(100);
        char * query  = (char *)malloc(400);

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        struct Header msgHeader;
        int offset = getHeaderFromChar(command,&msgHeader);
        if(offset!=90)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
            return answer;
        }

        int result = 0;


        // check if user has access to the group
        sqlite3_stmt *statement;
        if(msgHeader.userType == '0') //Receiver is a user, not a group
        {
            sprintf(query,"SELECT Id FROM Users WHERE Login='%s'",msgHeader.receiver);
        }
        else
        {

            sprintf(query,"SELECT Id, Private, Owner_Id FROM Groups WHERE Name='%s'",msgHeader.receiver);
        }

        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // get info
                    if(msgHeader.userType == '0') //Receiver is a user, not a group
                    {
                        const int *id = (const int*) sqlite3_column_int(statement,0);
                        result = (int)id;
                    }
                    else
                    {
                        const int *id = (const int*) sqlite3_column_int(statement,0);
                        const int *private = (const int*) sqlite3_column_int(statement,1);
                        const int *owner = (const int*) sqlite3_column_int(statement,2);

                        if(private == 0)
                        {
                            result = (int)id;
                        }
                        else
                        {
                            if(owner==*loginState)
                            {
                                result = (int)id;
                            }
                        }
                    }

            } else if (returnValue == SQLITE_DONE) {

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        // No access
        if(result == 0)
        {
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGDEST);
            return answer;
        }
        //End check


        // create message
        if(msgHeader.userType == '0') //Receiver is a user, not a group
        {
            sprintf(query,"INSERT INTO Messages VALUES (NULL,%d,%d,0,0,DATETIME('now'),'%s')",*loginState,result,msgHeader.date);
        }
        else //Receiver is a group
        {
            sprintf(query,"INSERT INTO Messages VALUES (NULL,%d,0,%d,0,DATETIME('now'),'%s')",*loginState,result,msgHeader.date);
        }
        returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        sprintf(query,"SELECT last_insert_rowid()");
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if (returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer, "%s%ld %s", OK, getCommandNumber(), DBERROR);
            return answer;
        }

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // get info
                    const int *id = (const int*) sqlite3_column_int(statement,0);

                    result = (int)id;

            } else if (returnValue == SQLITE_DONE) {

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row
        
        if(result > 0)
        {
            char msg[300];
            int ind=0;
           //offset should be equal 90 - header size. We are starting from 91
            offset += 1;
            for(ind=0;ind<msgHeader.bytesOfMessage;ind++)
            {
                msg[ind] = command[offset+ind];
            }
            msg[ind] = '\0';
            
            sprintf(query,"INSERT INTO MessageContents VALUES(NULL,'%s',%d)",msg,result);
            returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);

            if (returnValue)
            {
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                free(query);
                sprintf(answer, "%s%ld %s", OK, getCommandNumber(), DBERROR);
                return answer;
            }

            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),MSGSENT);

        }
        else
        {
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGDEST);
        }

        return answer;
    }

    char * ResponseListMyOwnMessages(int * loginState)
    {
        int returnValue;

        char * answer = (char *)malloc(50);
        char * query  = (char *)malloc(200);

        int result = 0;

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        // Check the number
        sqlite3_stmt *statement;
        sprintf(query,"SELECT COUNT(*) as privmsg FROM Messages WHERE Sender_Id = %d",*loginState);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                int col=0;
                for (col; col < cols; col++)
                {
                    const int *val = (const int*) sqlite3_column_int(statement, col);

                    //has private messages
                    if(val>=0)
                    {
                        result = (int)val;
                    }
                }
            } else if (returnValue == SQLITE_DONE) {

                free(query);
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        sprintf(answer,"%s%ld %d",OK,getCommandNumber(),result);
        return answer;
    }

    char * ResponseGetMyOwnSpecificMessage(char * command, int * loginState)
    {
        int returnValue;
        int msgid=0;
        char * answer = (char *)malloc(400);
        char * query  = (char *)malloc(400);

        struct Header msgHeader;
        char message[300];

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%d",&msgid);

        // Wrong command syntax
        if (returnValue != 1)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = -1;

        // Check message type
        sqlite3_stmt *statement;
        sprintf(query,"SELECT Id,Receiver_Type FROM Messages WHERE Sender_Id = %d ORDER BY Id LIMIT %d,1",*loginState,msgid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want
                    const int *val = (const int*) sqlite3_column_int(statement, 1);
                    const int *knownMsgId = (const int*) sqlite3_column_int(statement, 0);

                    result = val;
                    msgid = knownMsgId;

            } else if (returnValue == SQLITE_DONE) {

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        if(result==-1) // should be 0 (user) or 1 (group)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
            return answer;
        }

        // get message
        if(result == 0) //user receiver
        {
            sprintf(query,"SELECT msg.Id,msg.Send_Date,rec.Login,snd.Login,msgc.Message_Text FROM Messages AS msg INNER JOIN MessageContents AS msgc ON msg.Id = msgc.Messages_Id INNER JOIN Users AS rec ON msg.Receiver_Id = rec.Id INNER JOIN Users AS snd ON msg.Sender_Id = snd.Id WHERE msg.Id=%d",msgid);
        }
        else if(result == 1)//group receiver
        {
           sprintf(query,"SELECT msg.Id,msg.Send_Date,rec.Name,snd.Login,msgc.Message_Text FROM Messages AS msg INNER JOIN MessageContents AS msgc ON msg.Id = msgc.Messages_Id INNER JOIN Groups AS rec ON msg.Receiver_Groups_Id = rec.Id INNER JOIN Users AS snd ON msg.Sender_Id = snd.Id WHERE  msg.Id=%d",msgid);
        }

        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        int done=0;

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // Set the header
                    const int *Id = (const int*) sqlite3_column_int(statement, 0);
                    const char *date = (const char*) sqlite3_column_text(statement,1);
                    const char *sender = (const char*) sqlite3_column_text(statement,2);
                    const char *receiver = (const char*) sqlite3_column_text(statement,3);
                    const char *msgtxt = (const char*) sqlite3_column_text(statement,4);

                    msgHeader.bytesOfMessage = getMessageSize(msgtxt);
                    strcpy(msgHeader.date,date);
                    msgHeader.messageAlreadyRead='0';
                    strcpy(msgHeader.sender,sender);
                    strcpy(msgHeader.receiver,receiver);
                    if(result==0)
                    {
                        msgHeader.userType = '0';
                    }
                    else
                    {
                        msgHeader.userType = '1';
                    }
                    strcpy(message,msgtxt);
                    done = 1;

            } else if (returnValue == SQLITE_DONE) {

                if(done==0)
                {
                    free(query);
                    sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
                    return answer;
                }
                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        sprintf(answer,"%s%ld %s %s",OK,getCommandNumber(),getCharHeader(&msgHeader),message);

        return answer;
    }

    char * ResponseDeleteMyOwnSpecificMessage(char * command, int * loginState)
    {
        int returnValue;
        int msgid=0;
        char * answer = (char *)malloc(100);
        char * query  = (char *)malloc(300);

        struct Header msgHeader;
        char message[300];

        // not logged in
        if (*loginState <=0)
        {
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            return answer;
        }

        returnValue = sscanf(command,"%d",&msgid);

        // Wrong command syntax
        if (returnValue != 1)
        {
            free(query);
            sprintf(answer,"%s%ld",KO,getCommandNumber());
            return answer;
        }

        int result = 0;


        // delete the message
        sqlite3_stmt *statement;
        sprintf(query,"SELECT msg.Id FROM Messages AS msg WHERE msg.Sender_Id = %d ORDER BY msg.Id LIMIT %d,1",*loginState,msgid);
        returnValue = sqlite3_prepare_v2(sqlServerHandle,query,-1,&statement,0);
        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        // Read the number of rows fetched
        int cols = sqlite3_column_count(statement);

        // Basic SQLITE fetch row
        while (1) {
            // fetch a row's status
            returnValue = sqlite3_step(statement);

            if (returnValue == SQLITE_ROW) {
                // SQLITE_ROW means fetched a row
                // sqlite3_column_text returns a const void* , typecast it to the things you want

                    // Set the header
                    const int *Id = (const int*) sqlite3_column_int(statement, 0);
                  
                    result = (int)Id;

            } else if (returnValue == SQLITE_DONE) {

                break;
            } else {
                // Some error encountered
                free(query);
                MessagePrint(sqlite3_errmsg(sqlServerHandle));
                sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
                return answer;
            }
        }
        // END // Basic SQLITE fetch row

        if(result == 0)
        {
            free (query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),WRONGARG);
            return answer;
        }

        sprintf(query,"DELETE FROM Messages WHERE Id=%d",result);
        returnValue = sqlite3_exec(sqlServerHandle,query,0,0,0);

        if(returnValue)
        {
            MessagePrint(sqlite3_errmsg(sqlServerHandle));
            free(query);
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),DBERROR);
            return answer;
        }

        sprintf(answer,"%s%ld %s",OK,getCommandNumber(),MSGDELETED);
        return answer;
    }

    char* GetWrongResponse()
    {
        return strdup(KORESPONSE);
    }

    // Interprets the command send by a client and gives the
    // right response for him.
    char* GetServerResponse(char *command, int *loginState, int *responseNeeded)
    {
        char mainCommand[15];
        char * commandContent1 = (char *) malloc(300);
        int i=0;
        int zeroBasedIndex=0;
        char answer[100];

        *responseNeeded = 0;

        for(i;command[i]!='\0' && command[i]!='\n';i++)
        {
            if(command[i] != ' ') //space
            {
                mainCommand[i] = command[i];
            }
            else
            {
                break;
            }
        }
        
        mainCommand[i++] = '\0';

        if(command[i]!= '\0')
        {
            zeroBasedIndex=0;
            for (i; command[i] != '\0'  && command[i]!='\n'; i++)
            {
                commandContent1[zeroBasedIndex++] = command[i];
            }
             commandContent1[zeroBasedIndex] = '\0';
        }

    /*
      TODO: Choose the right function to handle the command
        REGISTER
        LOGIN
        PASS
        LISTPRIV
        LISTGROUP
        LISTGROUPS
        LISTUSRGROUPS
        GETPRIVMSG
        GETGRMSG
        GETGROUPS
        GETUSRGROUPS
        SETUSRGROUP
        SETGROUP
        MODGROUP
        SENDMSG
        LISTMYMSG
        GETMYMSG
        DELMYMSG
    */

        if(!strcmp(mainCommand,HELLO))
        {
            *responseNeeded = 0;
            return ResponseHello();
        }

        if(!strcmp(mainCommand,REGISTER))
        {
            *responseNeeded = 1;
            return ResponseRegister(commandContent1,loginState);
        }
        
        if(!strcmp(mainCommand,LOGIN))
        {
            *responseNeeded = 1;
            return ResponseLogin(commandContent1,loginState);
        }

        if(!strcmp(mainCommand,PASS))
        {
            *responseNeeded = 1;
            return ResponsePassword(commandContent1,loginState);
        }

        if(*loginState>0)
        {
            *responseNeeded = 1;
            if(!strcmp(mainCommand,LISTPRIV)) return ResponseListMyPrivateMessages(loginState);
            if(!strcmp(mainCommand,LISTGROUP)) return ResponseListMyGroupMessages(commandContent1, loginState);
            if(!strcmp(mainCommand,LISTGROUPS)) return ResponseListAllGroups(loginState);
            if(!strcmp(mainCommand,LISTUSRGROUPS)) return ResponseListMyGroups(loginState);
            if(!strcmp(mainCommand,GETPRIVMSG)) return ResponseGetSpecificPrivateMessage(commandContent1, loginState);
            if(!strcmp(mainCommand,GETGRMSG)) return ResponseGetSpecificGroupMessage(commandContent1, loginState);
            if(!strcmp(mainCommand,GETGROUPS)) return ResponseSpecificGroup(commandContent1, loginState);
            if(!strcmp(mainCommand,GETUSRGROUPS)) return ResponseSpecificUserGroup(commandContent1, loginState);

            if(!strcmp(mainCommand,SETUSRGROUP)) return ResponseSetUserToGroup(commandContent1, loginState);
            if(!strcmp(mainCommand,SETGROUP)) return ResponseSetNewGroup(commandContent1, loginState);
            if(!strcmp(mainCommand,MODGROUP)) return ResponseModifyExistingGroup(commandContent1, loginState);
            if(!strcmp(mainCommand,SENDMSG)) return ResponseSendMessage(commandContent1, loginState);
            if(!strcmp(mainCommand,LISTMYMSG)) return ResponseListMyOwnMessages(loginState);
            if(!strcmp(mainCommand,GETMYMSG)) return ResponseGetMyOwnSpecificMessage(commandContent1, loginState);
            if(!strcmp(mainCommand,DELMYMSG)) return ResponseDeleteMyOwnSpecificMessage(commandContent1, loginState);
        }
        else
        {
            *responseNeeded = 0;
            sprintf(answer,"%s%ld %s",OK,getCommandNumber(),NOUSER);
            *loginState = 0;
            return strdup(answer);
        }
        
        *responseNeeded = 0;
        sprintf(answer,"%s%ld",KO,getCommandNumber());
        return answer;
    }




